package com.link2room.blaster.service.impl;

import com.link2room.blaster.dto.innerUse.InmailBaseDto;
import com.link2room.blaster.service.IInmailService;
import com.link2room.common.constant.DefaultValue;
import com.link2room.common.dao.ICommonDao;
import com.link2room.common.exception.SysException;
import com.link2room.common.jpa.condition.ConditionDetail;
import com.link2room.common.jpa.condition.L2RCondition;
import com.link2room.common.jpa.criteria.CriteriaUtil;
import com.link2room.common.jpa.result.QueryResult;
import com.link2room.common.service.ICommonService;
import com.link2room.common.util.ClassConverUtil;
import com.link2room.blaster.dto.inMail.InmailCountDto;
import com.link2room.blaster.entity.InMailBaseEntity;
import com.link2room.blaster.entity.InMailDetailEntity;
import com.link2room.blaster.entity.InMailReceiveEntity;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.integration.redis.util.RedisLockRegistry;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.stream.Collectors;

import static com.link2room.enums.exception.BlasterSysExceptionEnum.CREATE_INMAIL_TERROR;


/**
 * Created by LN on 2017/6/29.16:27
 */
@Component("inmailService")
public class InmailServiceImpl implements IInmailService {
    @Autowired
    private RedisLockRegistry inmailIdGenerateLock;
    @Resource
    private ICommonService commonService;

    @Resource
    private ICommonDao commonDao;


    private static final String noType = "in_mail";

    @Override
    public String generateInmailId() throws Exception {
        Lock lock = inmailIdGenerateLock.obtain(noType);
        if (lock.tryLock(300, TimeUnit.MILLISECONDS)) {
            try {
                List params = new ArrayList<>();
                params.add(noType);
                String no = commonService.findOneFieldByProcedure("create_No", params);
                return no;
            } finally {
                lock.unlock();
            }
        } else {
            throw new SysException(CREATE_INMAIL_TERROR, "[noType] = " + noType);
        }
    }

    @Override
    @Transactional
    public void createInmail(InmailBaseDto inmail, String inmailId, List<String> receivers) throws Exception {
        InMailBaseEntity baseEntity = new InMailBaseEntity();
        baseEntity.setLhotelGroupCode(inmail.getLhotelGroupCode());
        baseEntity.setLhotelCode(inmail.getLhotelCode());
        baseEntity.setTitle(inmail.getTitle());
        baseEntity.setHasDone(DefaultValue.F);
        baseEntity.setHasRead(DefaultValue.F);
        baseEntity.setMailId(inmailId);
        baseEntity.setType(inmail.getType());

        InMailDetailEntity detailEntity = new InMailDetailEntity();
        detailEntity.setMailId(inmailId);
        detailEntity.setMessage(inmail.getMessage());
        detailEntity.setLhotelGroupCode(inmail.getLhotelGroupCode());
        detailEntity.setLhotelCode(inmail.getLhotelCode());

        List<InMailReceiveEntity> receiveEntitys = new ArrayList<>();
        receivers.forEach(receiverCode -> {
            InMailReceiveEntity receive = new InMailReceiveEntity();
            receive.setMailId(inmailId);
            receive.setReceiverCode(receiverCode);
            receive.setHasDone(DefaultValue.F);
            receive.setHasRead(DefaultValue.F);
            receive.setLhotelGroupCode(inmail.getLhotelGroupCode());
            receive.setLhotelCode(inmail.getLhotelCode());
            receiveEntitys.add(receive);
        });

        commonDao.save(baseEntity);
        commonDao.save(detailEntity);
        commonDao.saveList(receiveEntitys);
    }

    @Override
    public List<String> findReceiver(String inmailId) throws Exception {
        InMailReceiveEntity find = new InMailReceiveEntity();
        find.setMailId(inmailId);
        QueryResult<InMailReceiveEntity> qres = commonService.findAllEQ(InMailReceiveEntity.class, find);
        if (qres == null || CollectionUtils.isEmpty(qres.getResultlist())) {
            return Collections.emptyList();
        } else {
            return qres.getResultlist().stream()
                    .map(InMailReceiveEntity::getReceiverCode)
                    .collect(Collectors.toList());
        }
    }

    @Override
    public List<InmailBaseDto> findInmailBaseByInmailId(List<String> inmailIds) throws Exception {
        L2RCondition condition = new L2RCondition();
        condition.setAndConditions(
                new ConditionDetail[]{new ConditionDetail(InMailBaseEntity.InMailBaseEntity_.mailId.toString(), CriteriaUtil.Operator.IN, inmailIds)}
        );
        QueryResult<InMailBaseEntity> qres = commonDao.findAll(InMailBaseEntity.class, CriteriaUtil.getCriteria(condition), null, null, null, null);
        if (qres == null || CollectionUtils.isEmpty(qres.getResultlist())) {
            return Collections.emptyList();
        } else {
            return qres.getResultlist().stream()
                    .map(entity -> {
                        InmailCountDto dto = ClassConverUtil.copyProperties(entity, InmailCountDto.class);
                        dto.setInmailId(entity.getMailId());
                        return dto;
                    })
                    .collect(Collectors.toList());
        }
    }

    @Override
    @Transactional
    public void readInmail(String userCode, String inmailId) throws Exception {
        InMailReceiveEntity find = new InMailReceiveEntity();
        find.setReceiverCode(userCode);
        find.setMailId(inmailId);
        find.setHasRead(DefaultValue.F);
        InMailReceiveEntity receiveEntity = commonDao.findOne(InMailReceiveEntity.class, CriteriaUtil.getCriteriaAllEQ(find));
        if(receiveEntity == null){
            return;
        }
        receiveEntity.setHasRead(DefaultValue.T);
        commonDao.merge(receiveEntity);
    }

    @Override
    public boolean hasReadAll(String inmailId) throws Exception {
        InMailReceiveEntity countNotReadc = new InMailReceiveEntity();
        countNotReadc.setMailId(inmailId);
        countNotReadc.setHasRead(DefaultValue.F);
        long countAll = commonDao.getCount(InMailReceiveEntity.class, CriteriaUtil.getCriteriaAllEQ(countNotReadc), null);

        return countAll == 0 ;
    }

    @Override
    @Transactional
    public void readBaseInamil(String inmailId) throws Exception {
        InMailBaseEntity baseFind = new InMailBaseEntity();
        baseFind.setMailId(inmailId);
        baseFind.setHasRead(DefaultValue.F);
        InMailBaseEntity baseEntity = commonDao.findOne(InMailBaseEntity.class, CriteriaUtil.getCriteriaAllEQ(baseFind));
        if(baseEntity!=null){
            baseEntity.setHasRead(DefaultValue.T);
            commonDao.merge(baseEntity);
        }
    }

    @Override
    @Transactional
    public void doInmail(String userCode, String inmailId) throws Exception {
        InMailReceiveEntity find = new InMailReceiveEntity();
        find.setReceiverCode(userCode);
        find.setMailId(inmailId);
        find.setHasDone(DefaultValue.F);
        InMailReceiveEntity receiveEntity = commonDao.findOne(InMailReceiveEntity.class, CriteriaUtil.getCriteriaAllEQ(find));
        if(receiveEntity == null){
            return;
        }
        receiveEntity.setHasDone(DefaultValue.T);
        commonDao.merge(receiveEntity);
    }

    @Override
    public boolean hasDoneAll(String inmailId) throws Exception {
        InMailReceiveEntity countNotReadc = new InMailReceiveEntity();
        countNotReadc.setMailId(inmailId);
        countNotReadc.setHasDone(DefaultValue.F);
        long countAll = commonDao.getCount(InMailReceiveEntity.class, CriteriaUtil.getCriteriaAllEQ(countNotReadc), null);

        return countAll == 0 ;
    }

    @Override
    @Transactional
    public void doBaseInamil(String inmailId) throws Exception {
        InMailBaseEntity baseFind = new InMailBaseEntity();
        baseFind.setMailId(inmailId);
        baseFind.setHasDone(DefaultValue.F);
        InMailBaseEntity baseEntity = commonDao.findOne(InMailBaseEntity.class, CriteriaUtil.getCriteriaAllEQ(baseFind));
        if(baseEntity!=null){
            baseEntity.setHasDone(DefaultValue.T);
            commonDao.merge(baseEntity);
        }
    }

    @Override
    public long countInmail(String userCode, String hasRead, String hasDone) throws Exception {
        InMailReceiveEntity find = new InMailReceiveEntity();
        find.setReceiverCode(userCode);
        find.setHasDone(hasDone);
        find.setHasRead(hasRead);
        return commonDao.getCount(InMailReceiveEntity.class,CriteriaUtil.getCriteriaAllEQ(find),null);
    }
}
